﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraEditors;

namespace ComponentsLib
{
    public partial class BaseUIControl : DevExpress.XtraEditors.XtraUserControl
    {
        private enum EventMode
        {
            Moving,
            ResizeWidth,
            ResizeHeight,
            ResizeNWSE,
            ResizeNESW,
            Nothing
        }
        private EventMode mode;
        private EventMode Mode { get { return mode; } set { mode = value; ChangeCursor(); } }
        private Size preCursor;
        private Point preLocation;
        private Size preSize;
        private bool resizing;
        private int resizeType;
        private readonly int border;
        public virtual bool Movable { get; set; }
        public virtual bool Resizable { get; set; }
        public int Thickness { get; set; }

        public delegate bool AcceptMoving(Point currPos);

        public event AcceptMoving OnAcceptMoving;

        public BaseUIControl()
        {
            InitializeComponent();
            Mode = EventMode.Nothing;
            resizing = false;
            border = this.Padding.All > 0 ? this.Padding.All : 5;
            Thickness = 5;            
            //this.SetStyle(ControlStyles.Selectable, true);
            this.SetStyle(ControlStyles.UserPaint, true);
            this.SetStyle(ControlStyles.SupportsTransparentBackColor, true);
            this.BackColor = Color.Transparent;
        }

        private bool SameColor(Color c1, Color c2)
        {
            //return Math.Abs(c1.B - c2.B) < 3 && Math.Abs(c1.G - c2.G) < 3 && Math.Abs(c1.R - c2.R) < 3;
            return Math.Abs(c1.GetBrightness() - c2.GetBrightness()) < 3 && Math.Abs(c1.GetHue() - c2.GetHue()) < 3 && Math.Abs(c1.GetSaturation() - c2.GetSaturation()) < 3;
        }

        private bool IsTransColor(Color c, Color sample)
        {
            if (c.Equals(Color.Transparent))
            {
                return true;
            }

            
            if (c.A < 255)
            {
                return true;
            }
            return false;
            //return SameColor(c, sample);
        }

        public virtual void CreateControlShape(Image Shape, int width, int height, Color transColor)
        {
            using (System.Drawing.Drawing2D.GraphicsPath myGraphicsPath = new System.Drawing.Drawing2D.GraphicsPath())
            {
                //myGraphicsPath.AddEllipse(new Rectangle(0, 0, 75, 75));
                //myGraphicsPath.AddPie(new Rectangle(0, 0, fixedWidth, fixedHeight), 0, 360);
                //myGraphicsPath.AddEllipse(new Rectangle(0, 0, 125, 125));
                //myGraphicsPath.AddEllipse(new Rectangle(75, 75, 20, 20));
                //myGraphicsPath.AddEllipse(new Rectangle(120, 0, 125, 125));
                //myGraphicsPath.AddEllipse(new Rectangle(145, 75, 20, 20));
                //Change the button's background color so that it is easy
                //to see.
                if (Shape != null)
                {
                    using (Bitmap image = new Bitmap(width, height))
                    {
                        using (Graphics g = Graphics.FromImage(image))
                        {
                            g.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.HighQuality;
                            g.DrawImage(Shape, 0, 0, image.Width, image.Height);
                        }
                        for (int y = 0; y < image.Height; y++)
                        {
                            int s = 0;
                            int f = image.Width - 1;
                            while (s <= f && IsTransColor(image.GetPixel(s, y), transColor))
                                s++;
                            while (s <= f && IsTransColor(image.GetPixel(f, y), transColor))
                                f--;
                            myGraphicsPath.AddRectangle(new Rectangle(s, y, f - s, 1));
                        }
                    }
                }
                Region = new Region(myGraphicsPath);
            }
        }

        private void BaseUIControl_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                preCursor = new Size(e.Location);
                preLocation = this.Location;
                preSize = this.Size;
                if (Mode == EventMode.Nothing && Movable)
                {
                    Mode = EventMode.Moving;
                }
                else if (Resizable)
                {
                    resizing = (Mode != EventMode.Moving);
                }
            }
        }

        private void BaseUIControl_MouseUp(object sender, MouseEventArgs e)
        {

            if (Mode == EventMode.Moving)
            {
                bool accept = true;
                if (OnAcceptMoving != null)
                {
                    accept = OnAcceptMoving.Invoke(this.Location);
                }

                if (accept)
                {

                }
                else
                {
                    this.Location = preLocation;
                }
            }

            Mode = EventMode.Nothing;
            resizing = false;
            resizeType = 0;  
        }

        private void BaseUIControl_MouseMove(object sender, MouseEventArgs e)
        {
            Control content = sender as Control;
            if (Mode == EventMode.Moving)
            {
                this.Location += new Size(e.Location - preCursor);
                return;
            }

            #region oldMethod
            //if (!resizing)
            //{                
            //    if ((e.X >= (this.Width - 5) && e.Y >= (this.Height - 5)))
            //    {
            //        Mode = EventMode.ResizeNWSE;
            //    }
            //    else if (e.X >= (this.Width - 5))
            //    {
            //        Mode = EventMode.ResizeWidth;

            //    }
            //    else if (e.Y >= (this.Height - 5))
            //    {
            //        Mode = EventMode.ResizeHeight;
            //    }
            //    else
            //    {
            //        Mode = EventMode.Nothing;
            //    }
            //}
            //
            //if (resizing)
            //{
            //    switch (Mode)
            //    {
            //        case EventMode.ResizeWidth:
            //            this.Width = e.X;
            //            break;
            //        case EventMode.ResizeHeight:
            //            this.Height = e.Y;
            //            break;
            //        default:
            //            this.Height = e.Y;
            //            this.Width = e.X;
            //            break;
            //    }
            //}
            #endregion

            if (!resizing && Resizable)
            {
                if (((content.Size == this.Size) && e.X <= border && e.Y <= border) ||
                    (e.X >= (this.Width - border) && e.Y >= (this.Height - border)))
                {
                    Mode = EventMode.ResizeNWSE;
                    resizeType = e.X <= border ? 1 : 0;
                }
                else if (((content.Size == this.Size) && e.X <= border && e.Y >= (this.Height - border)) ||
                    ((content.Size == this.Size) && e.X >= (this.Width - border) && e.Y <= border))
                {
                    Mode = EventMode.ResizeNESW;
                    if (e.X <= border)
                    {
                        resizeType = 1;
                    }
                    else if (e.Y <= border)
                    {
                        resizeType = 2;
                    }
                }
                else if (((content.Size == this.Size) && e.X <= border) || e.X >= (this.Width - border))
                {
                    Mode = EventMode.ResizeWidth;
                    resizeType = e.X <= border ? 1 : 0;
                }
                else if (((content.Size == this.Size) && e.Y <= border) || e.Y >= (this.Height - border))
                {
                    Mode = EventMode.ResizeHeight;
                    resizeType = e.Y <= border ? 1 : 0;
                }
                else
                {
                    Mode = EventMode.Nothing;
                }
            }

            if (resizing)
            {
                if (resizeType > 0)
                {
                    Size tmp = new Size(e.X - preCursor.Width, e.Y - preCursor.Height);
                    switch (Mode)
                    {
                        case EventMode.ResizeWidth:
                            if (this.Width - tmp.Width >= border * Thickness)
                            {
                                this.Location = new Point(this.Location.X + tmp.Width, this.Location.Y);
                                this.Width -= tmp.Width;
                            }
                            break;
                        case EventMode.ResizeHeight:
                            if (this.Height - tmp.Height >= border * Thickness)
                            {
                                this.Location = new Point(this.Location.X, this.Location.Y + tmp.Height);
                                this.Height -= tmp.Height;
                            }
                            break;
                        case EventMode.ResizeNESW:
                            if (resizeType == 1)
                            {
                                if (this.Width - tmp.Width >= border * Thickness && e.Y >= border * Thickness)
                                {
                                    this.Location = new Point(this.Location.X + tmp.Width, this.Location.Y);
                                    this.Width -= tmp.Width;
                                    this.Height = e.Y + border;
                                }
                            }
                            else
                            {
                                if (this.Height - tmp.Height >= border * Thickness && e.X >= border * Thickness)
                                {
                                    this.Location = new Point(this.Location.X, this.Location.Y + tmp.Height);
                                    this.Width = e.X + border;
                                    this.Height -= tmp.Height;
                                }
                            }
                            break;
                        case EventMode.ResizeNWSE:
                            if (this.Height - tmp.Height >= border * Thickness && this.Width - tmp.Width >= border * Thickness)
                            {
                                this.Location = new Point(this.Location.X + tmp.Width,
                                    this.Location.Y + tmp.Height);
                                this.Width -= tmp.Width;
                                this.Height -= tmp.Height;
                            }
                            break;
                    }
                }
                else
                {
                    switch (Mode)
                    {
                        case EventMode.ResizeWidth:
                            if (e.X >= border * Thickness)
                            {
                                this.Width = e.X + border;
                            }
                            break;
                        case EventMode.ResizeHeight:
                            if (e.Y >= border * Thickness)
                            {
                                this.Height = e.Y + border;
                            }
                            break;
                        default:
                            if (e.X >= border * Thickness)
                            {
                                this.Width = e.X + border;
                            }
                            if (e.Y >= border * Thickness)
                            {
                                this.Height = e.Y + border;
                            }                            
                            break;
                    }
                }

            }
        }


        private void ChangeCursor()
        {
            switch (Mode)
            {
                case EventMode.Moving:
                    this.Cursor = Cursors.SizeAll;
                    break;
                case EventMode.ResizeWidth:
                    this.Cursor = Cursors.SizeWE;
                    break;
                case EventMode.ResizeHeight:
                    this.Cursor = Cursors.SizeNS;
                    break;
                case EventMode.ResizeNWSE:
                    this.Cursor = Cursors.SizeNWSE;
                    break;
                case EventMode.ResizeNESW:
                    this.Cursor = Cursors.SizeNESW;
                    break;
                case EventMode.Nothing:
                    this.Cursor = Cursors.Default;
                    break;
                default:
                    this.Cursor = Cursors.Default;
                    break;
            }
        }
        private void SetMovableEvent(Control control)
        {
            foreach (Control item in control.Controls)
            {
                item.MouseDown -= BaseUIControl_MouseDown;
                item.MouseUp -= BaseUIControl_MouseUp;
                item.MouseMove -= BaseUIControl_MouseMove;
                item.ControlAdded -= BaseUIControl_ControlAdded;
                item.MouseDown += BaseUIControl_MouseDown;
                item.MouseUp += BaseUIControl_MouseUp;
                item.MouseMove += BaseUIControl_MouseMove;
                if (!(item is DevExpress.XtraEditors.BaseControl))
                {
                    item.ControlAdded += BaseUIControl_ControlAdded;
                    SetMovableEvent(item);    
                }
                
            }
        }

        private void BaseUIControl_Load(object sender, EventArgs e)
        {
            SetMovableEvent(sender as Control);            
        }

        private void BaseUIControl_ControlAdded(object sender, ControlEventArgs e)
        {
            //SetMovableEvent(sender as Control);
        }

    }    

}
